static int bit_count;
static char byte_buff;
static int byte_buff_filled = 0;

int log2_ceil(int n)
{
  if(n<0)
    {
      printf("Error at %s:n<0.\n",__func__);
      exit(EXIT_FAILURE);
    }
  if(n<1)
    {
      //      printf("Warning at %s:n<1 (negative results not available)",__func__);
      return 1;
    }
  int res = 1;
  int tmp = 2;
  while(tmp<n)
    {
      res++;
      tmp=(tmp<<1);
    }
  return res;
}

//TODO doxy
void flush_byte(FILE * file)
{
  char * aux;
  aux = (char *) & (byte_buff);
  fwrite(aux,1,1,file);
}

/**
 * Prints integer in binary format (as binary data)
 *
 * @param n : Number to convert to binary.
 * @param digits : Number of bits wanted.
 * @param dest : Where to write to.
 *
 * @return :  ERROR_OK or ERROR_FAILURE regarding fprintf.
 */
void dec_to_bin_print_bin(int n , int digits, int flush, FILE * file)
{
  int i=0 , b, retval;
  if(n<0)
    {
      perror("warning, negative n not expected\n");
      exit(EXIT_FAILURE);
    }
  if(file == NULL)
    {
      perror("File not open!");
      exit(EXIT_FAILURE);
    }

  bit_count = (digits>0)?bit_count+digits:bit_count;
  for(i=digits-1;i>=0;i--)
    {
      byte_buff = (byte_buff<<1)|(((1<<i)&n)!=0);
      byte_buff_filled++;
      if(byte_buff_filled==BPP)
	{
	  flush_byte(file);
	  byte_buff_filled = 0;
	  byte_buff = 0;
	}
    }
  if((byte_buff_filled<BPP) && flush)
    {
      flush_byte(file);
      byte_buff_filled = 0;
      byte_buff = 0;
    }
}

/**
 * Prints integer in binary format (as text data)
 *
 * @param n : Number to convert to binary.
 * @param digits : Number of bits wanted.
 * @param dest : Where to write to.
 *
 * @return :  ERROR_OK or ERROR_FAILURE regarding fprintf.
 */
void dec_to_bin_print(int n , int digits, FILE * dest)
{
  int i=0 , b, retval;
  if(n<0)
    {
      perror("warning, negative n not expected\n");
      exit(EXIT_FAILURE);
    }
  if(dest == NULL)
    {
      perror("File not opened!");
      exit(EXIT_FAILURE);
    }
  bit_count += digits;
  for(i=digits-1;i>=0;i--)
    {
      b = (((1<<i)&n)>0) ? 1 : 0 ;
      retval = fprintf(dest,"%u",b);
      retval = (retval < 0) ? ERROR_FAILURE : ERROR_OK;
      if(retval != ERROR_OK)
	{
	  perror("Could not write bits.");
	  exit(EXIT_FAILURE);
	}
    }
}

void header_write(PGMData * image,int N,FILE * file)
{
  dec_to_bin_print_bin(image->row,HEADER_WORD_LEN_IMAGE,0,file);
  dec_to_bin_print_bin(image->col,HEADER_WORD_LEN_IMAGE,0,file);
  dec_to_bin_print_bin(N,HEADER_WORD_LEN_N,0,file);
  dec_to_bin_print_bin(image->max_gray,BPP,0,file);
}

void header_read(PGMData * image,int * N,FILE * file)
{
  int current = 0, tmp = 0, iter, len_ref = HEADER_WORD_LEN_IMAGE;
  for(iter = 0; iter<(BPP+HEADER_WORD_LEN_N+2*(HEADER_WORD_LEN_IMAGE));iter++)
    {
      read_bit(&tmp,file);
      if((iter % len_ref) == (len_ref-1))
	{
	  switch (current)
	    {
	    case 0:
	      image->row = tmp;
	      break;
	    case 1:
	      image->col = tmp;
	      len_ref = HEADER_WORD_LEN_N;
	      break;
	    case 2:
	      *N = tmp;
	      break;
	    case 3:
	      image->max_gray = tmp;
	      break;
	    default:
	      printf("Read too much in: ",__FUNCTION__);
	      exit(EXIT_FAILURE);
	      break;
	    }
	  tmp = 0;
	  current++;
	}
    }
}

void read_bit_bin(int * var, FILE * file)
{
  int retval;
  if(byte_buff_filled > 0)
    {
      byte_buff_filled--;
      byte_buff = (byte_buff<<1);
    }
  else
    {
      retval = fread(&byte_buff,1,1,file);
      if(retval == 0){
	perror("Read error...");
	exit(EXIT_FAILURE);
      }
      byte_buff_filled = 7;
    }
  *var = (((*var)<<1) | ((byte_buff&0x80)==0x80));
}

//TODO doxy
void read_bit(int * var, FILE * file)
{
  read_bit_bin(var,file);
  // The following lines where used when printing 0 & 1
  //as char, for debugging.
  //  char tmp[1];
  //  fgets(tmp,2,file);
  //  *var = ( ((*var)<<1) | (strcmp(tmp,"1")==0) );
}

//TODO doxy
int adapt_golomb(int * A,int * n, int err, int N)
{
  if (*n==N)
    {
      *A=((*A)>>1);
      *n=((*n)>>1);
    }
  (*n)++;
  (*A)+=err;
  int retval;
  if ((*A)<0){
          printf("adapt_golomb\n");
  }
  double aux = ((double) (*A))/ ((double) (*n));
  if (aux==0)
      aux=0.1;
  retval = log2_ceil(aux);
  if (retval>6)
      retval=6;
  return (1<<retval);
}

int adapt_golomb_run(int * n0,int * n1, int err,int mrun, int Nrun)
{
  if (*n1==Nrun)
    {
      *n0=((*n0)>>1);
      *n1=((*n1)>>1);
    }
  if (!(err==mrun))
    (*n1)++;
  *n0=(*n0)+err;
  int retval;
  double beta_mle = (*n0)/(*n1);
  retval = (int) round(log2((*n0)/(*n1)+0.5)-1);
  retval = retval<2?2:retval;
  return (1<<retval);
}

int unfold_error(int err)
{
  int retval = ((err+1)>>1);
  retval = (err&1) ? -retval : retval;
  return retval;
}

int fold_error(int err)
{
  if(err<0)
    err=(-2)*err - 1;
  else
    err=2*err;
  return err;
}